package com.jwww.support.mybatis;

import com.jwww.support.helper.JarHelper;
import com.jwww.support.mybatis.beans.MapResultItem;

import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger;

import java.io.File;
import java.io.IOException;
import java.net.URL;
import java.util.*;
import java.util.jar.JarFile;

/**
 * mybatismapper数据库字段与实体字段映射关系转换工具
 * @author jwww
 * @date 2015年5月7日上午11:30:42
 * @description <br>
 * Copyright (c) 2015, vakinge@gmail.com.
 */
public class MybatisMapperResultConverter {

	
	private static final Logger log = Logger.getLogger(MybatisMapperResultConverter.class);
	
	private static Map<String, Map<String, String>> caches = new HashMap<String, Map<String,String>>();
	
	
	
	public static String columnToPropName(Class<?> entityClass,String columnName){
		cacheData();
		if(caches.containsKey(entityClass.getName())){
			return caches.get(entityClass.getName()).get(columnName);
		}
		return null;
	}
	
	public static String property2ColumnName(Class<?> entityClass,String propName){
		cacheData();
		Map<String, String> map = caches.get(entityClass.getName());
		if(map != null){
			for (String columnName : map.keySet()) {
				if(propName.equals(map.get(columnName)))return columnName;
			}
		}
		return null;
	}
	
	private static void cacheData(){
		if(caches.isEmpty()){
			try {
				URL resource = Thread.currentThread().getContextClassLoader().getResource("mybatis-configuration.xml");
				
				if (resource != null) {			
					if (resource.getProtocol().equals("file")) {
						File file = new File(resource.getPath()).getParentFile();
						Collection<File> files = FileUtils.listFiles(file, new String[]{"xml"}, true);
						
						for (File f : files) {
							if(f.getName().endsWith("Mapper.xml")){
								cacheDataFromMapper(FileUtils.readLines(f));
							}
						}
					} else if (resource.getProtocol().equals("jar")) {
						String jarFilePath = resource.getFile();						
						jarFilePath	= jarFilePath.substring("file:".length(), jarFilePath.length() - "!/mybatis-configuration.xml".length());
						jarFilePath = java.net.URLDecoder.decode(jarFilePath, "UTF-8");

						JarFile jarFile = new JarFile(jarFilePath);
						
						List<String> fileNames = JarHelper.listFiles(jarFile, "Mapper.xml");
						if (fileNames != null && fileNames.size() > 0) {
							for (String fileName : fileNames) {
								List<String> lines = JarHelper.readLines(jarFile, fileName);
								
								cacheDataFromMapper(lines);
							}
						}
						
						jarFile.close();
					} else {
						log.error("mybatis-configuration.xml is in unsurport protocol");
					}															
				} else {
					log.error("can not find mybatis-configuration.xml");
				}				
			} catch (Exception e) {
				log.error(e.getMessage(), e);	
				
				throw new RuntimeException(e);
			}
		}
	}
	
	
	public static List<MapResultItem> parseColumnsFromResultMapLine(List<String> lines) throws IOException {
		
		List<MapResultItem> results = new ArrayList<MapResultItem>();
		String namespace = null,entityTypeName = null;
		for (String line : lines) {
			if(line == null || line.trim().length() == 0)continue;
			if(line.contains("</resultMap>"))break;
			if(line.contains("<mapper namespace")){
				namespace = line.replace("<mapper namespace=\"", "").replaceAll("\"\\s*\\>", "");
				System.out.println("parse result map-->"+namespace);
			}else if(line.contains("resultMap")){
				entityTypeName = line.split("type=\"")[1].replaceAll("\"\\s*\\>", "");
			}else if(line.contains("column=")){
				boolean isPrimaryKey = line.contains("<id");
				//<result column="parent_id" property="parentId" jdbcType="INTEGER" />
				String[] parts = line.split("\\s+");
				String col = null,prop = null,type = null;
				for (String part : parts) {
					if(part.contains("column")){
						col = part.split("column=\"")[1].replace("\"", "");
					}else if(part.contains("property")){
						prop = part.split("property=\"")[1].replace("\"", "");
					}else if(part.contains("jdbcType")){
						type = part.split("jdbcType=\"")[1].replaceAll("\"(\\s*\\>?)", "");
					}
				}
				if(col != null){
					MapResultItem resultItem = new MapResultItem(prop, col, type);
					resultItem.setPrimaryKey(isPrimaryKey);
					resultItem.setEntityName(entityTypeName);
					results.add(resultItem);
				}
			}
		}
		
		return results;
	}
	
	private static void cacheDataFromMapper(List<String> lines) throws IOException {				
		Map<String,String> resultRalate = new HashMap<String, String>();
		
		List<MapResultItem> list = parseColumnsFromResultMapLine(lines);
		String entityName = null;
		for (MapResultItem item : list) {
			if(entityName == null)entityName = item.getEntityName();
			resultRalate.put(item.getColumnName(), item.getPropertyName());
		}
		caches.put(entityName, resultRalate);
	}
	
	public static void main(String[] args) throws IOException {
		//
		File f = new File("D:/dao/crm/CompanyEntityMapper.xml");
		List<MapResultItem> list = parseColumnsFromResultMapLine(FileUtils.readLines(f));
		System.out.println(list);
	}
}
